﻿using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

namespace TCG
{
	/// <summary>
	/// 模型对象池，游戏中使用的模型对象应该从池中获取、释放，以提高性能并便用追踪。
	/// </summary>

	public class GameModelPool : MonoBehaviour
	{
		private static GameModelPool m_instance = null;

		public static GameModelPool instance
		{
			get 
			{
				if (m_instance == null)
				{
					m_instance = new GameObject ("_TCG_GameModelPool").AddComponent<GameModelPool> ();
				}
				return m_instance;
			}
		}

		/// <summary>
		/// 获取指定id的预设实例，通过回调requestCallback返回。
		/// </summary>

		public void GetModel (uint prefabId, Action<GameModelPooled> requestCallback)
		{
			IList<GameModelPooled> freedList = GetFreedList (prefabId, false);
			if (freedList != null && freedList.Count > 0) // 空闲列表中有，则下一帧返回
			{
				GameModelPooled result = freedList[freedList.Count - 1];
				freedList.RemoveAt (freedList.Count - 1);
				IList<GameModelPooled> usingList = GetUsingList (prefabId, true);
				usingList.Add (result);
				StartCoroutine (Co_GetModelCallback (result, requestCallback));
			}
			else // 空闲列表中没有，则新建并返回
			{
				AssetRequest request = new AssetRequest (prefabId, AssetType.UnityAssetBundle, delegate (AssetRequest _request) {
					GameObject prefab = _request.GetResultAsset<GameObject> ().asset;
					GameObject resultHost = GameObject.Instantiate (prefab) as GameObject;
					GameModelPooled result = resultHost.AddComponent<GameModelPooled> ();
					result.prefabAsset = _request.GetResultAsset<GameObject> ();
					IList<GameModelPooled> usingList = GetUsingList (prefabId, true);
					usingList.Add (result);
					requestCallback (result);
				});
				GameAssetsDatabase.instance.prefabDatabase.LoadAsset (request);
			}
		}

		/// <summary>
		/// 将实例放回池中。
		/// </summary>

		public void ReleaseModel (GameModelPooled model)
		{
			IList<GameModelPooled> freedList = GetFreedList (model.prefabAsset.id, true);
			freedList.Add (model);

			IList<GameModelPooled> usingList = GetUsingList (model.prefabAsset.id, false);
			usingList.Remove (model);
		}

		/// <summary>
		/// 销毁毁冲池中的所有闲置对象。
		/// </summary>

		public void DestroyAllFreed ()
		{
			foreach (KeyValuePair<uint, IList<GameModelPooled>> _pair in m_freedModelTable )
			{
				IList<GameModelPooled> list = _pair.Value;
				foreach (GameModelPooled _element in list)
				{
					GameAssetsDatabase.instance.prefabDatabase.ReleaseAsset (_element.prefabAsset);
					GameObject.Destroy (_element.gameObject);
				}
				list.Clear ();
			}
			m_freedModelTable.Clear ();
		}

		/// <summary>
		/// 获得和<paramref name="prefabId"/>相关联的空置对象列表，如不存在且<paramref name="createIfNone"/>为true，
		/// 则新建并返回。
		/// </summary>

		IList<GameModelPooled> GetFreedList (uint prefabId, bool createIfNone)
		{
			if (m_freedModelTable.ContainsKey (prefabId))
			{
				return m_freedModelTable[prefabId];
			}
			else if (createIfNone)
			{
				IList<GameModelPooled> list = new List<GameModelPooled> ();
				m_freedModelTable.Add (prefabId, list);
				return list;
			}
			return null;
		}

		/// <summary>
		/// 获得和<paramref name="prefabId"/>相关联的使用中对象列表，如不存在且<paramref name="createIfNone"/>为true，
		/// 则新建并返回。
		/// </summary>

		IList<GameModelPooled> GetUsingList (uint prefabId, bool createIfNone)
		{
			if (m_usingModelTable.ContainsKey (prefabId))
			{
				return m_usingModelTable[prefabId];
			}
			else if (createIfNone)
			{
				IList<GameModelPooled> list = new List<GameModelPooled> ();
				m_usingModelTable.Add (prefabId, list);
				return list;
			}
			return null;
		}

		IEnumerator Co_GetModelCallback (GameModelPooled result, Action<GameModelPooled> callback)
		{
			yield return null;
			callback (result);
		}

		/// <summary>
		/// 闲置的对象。
		/// </summary>

		IDictionary<uint, IList<GameModelPooled>> m_freedModelTable = new Dictionary<uint, IList<GameModelPooled>> ();

		/// <summary>
		/// 正在被使用的对象。
		/// </summary>

		IDictionary<uint, IList<GameModelPooled>> m_usingModelTable = new Dictionary<uint, IList<GameModelPooled>> ();
	}
}
